package com.link510.aitools.services;

import com.link510.aitools.core.listen.CWMListener;
import com.link510.aitools.framework.coder.MessageDecoder;
import com.link510.aitools.framework.coder.MessageEncoder;
import com.orhanobut.logger.Logger;

import org.greenrobot.eventbus.EventBus;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * Netty网络管理器
 */
public class NettyManager {

    private static NettyManager instance = null;

    private boolean isDebug = false;

    private Bootstrap mBootstrap = null;

    private ChannelFuture mChannelFuture = null;


    @Getter
    private TcpErrorState tcpErrorState = TcpErrorState.UnInitialized;

    //private CWMListener<Void> cwmListener = null;
    private ChannelInitializer<SocketChannel> mChannelInitializer = null;


    /**
     * 单例?
     *
     * @return NettyManager
     */
    public static NettyManager getInstance() {

        if (instance == null) {
            synchronized (NettyManager.class) {
                instance = new NettyManager();
            }
        }
        return instance;
    }


    /**
     * 构造方法
     */
    private NettyManager() {
        this(true);
    }

    /**
     * 构造方法
     *
     * @param isDebug 是否处于调试
     */
    private NettyManager(boolean isDebug) {

        this.isDebug = isDebug;

    }

    /**
     * 初始化网络
     *
     * @return
     */
    public boolean init() {

        try {



            this.mChannelInitializer = new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) {

                    //建立管道
                    ChannelPipeline channelPipeline = ch.pipeline();

                    channelPipeline.addLast(new MessageDecoder());
                    channelPipeline.addLast(new MessageEncoder());
                    channelPipeline.addLast(new SimpleChannelInboundHandler<String>() {
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, String msg) {

                            try {
                                Logger.e("消息下发:" + msg);
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }

                        }
                    });


                }
            };

            this.init(mChannelInitializer);
            return true;

        } catch (Exception ex) {

        }

        return false;
    }


    /**
     * 初始化网络
     */
    public void init(ChannelInitializer<SocketChannel> channelInitializer) {

        synchronized (NettyManager.class) {
            try {
                this.mBootstrap = new Bootstrap();
                this.mBootstrap.channel(NioSocketChannel.class);
                NioEventLoopGroup mGroup = new NioEventLoopGroup();
                this.mBootstrap.group(mGroup)
                        .option(ChannelOption.TCP_NODELAY, true)// 消息立即发出去
                        .option(ChannelOption.SO_REUSEADDR, true)
                        .handler(new LoggingHandler(isDebug ? LogLevel.DEBUG : LogLevel.INFO));

                if (channelInitializer != null) {
                    this.mBootstrap.handler(channelInitializer);
                }

                this.tcpErrorState = TcpErrorState.Initialized;
            } catch (Exception ex) {
                this.tcpErrorState = TcpErrorState.UnInitialized;
            }
        }
    }

    /**
     * TCP连接
     *
     * @param host 主机
     * @param port 端口
     */
    public void connect(String host, Integer port, CWMListener<Void> listener) {

        synchronized (NettyManager.class) {
            try {
                this.mChannelFuture = mBootstrap.connect(host, port)
                        .addListener(future -> {
                            boolean isSuccess = future.isSuccess();

                            if (isDebug) {
                                if (isSuccess) {
                                    this.tcpErrorState = TcpErrorState.Connect;
                                    Logger.e("Netty connect success.");
                                    EventBus.getDefault().post("Netty connect success.");
                                } else {
                                    Logger.e("Netty connect failed.");
                                    EventBus.getDefault().post("Netty connect failed.");
                                    this.tcpErrorState = TcpErrorState.Diconnect;
                                }
                            }

                            if (listener != null) {
                                try {
                                    listener.onSuccess("tcp connect success", null);
                                } catch (Exception ex) {
                                    Logger.e("TCP连接回调异常: ", ex);
                                }
                            }

                        })
                        .sync();
            } catch (Exception e) {
                this.tcpErrorState = TcpErrorState.Diconnect;
                e.printStackTrace();
            }
        }

    }

    /**
     * /**
     * 发送消息
     *
     * @param content 消息内容
     * @return 是否成功
     */
    public TcpErrorState write(Object content) {

        try {

            if (this.mChannelFuture == null) {
                return TcpErrorState.UnInitialized;
            }

            if (!this.mChannelFuture.channel().isOpen()) {
                return TcpErrorState.Diconnect;
            }

            synchronized (NettyManager.class) {
                new Thread(() -> {
                    try {
                        Thread.sleep(1);
                        NettyManager.this
                                .mChannelFuture.channel()
                                .writeAndFlush(content);
                    } catch (Exception ignored) {

                    }
                }).start();
            }

            return TcpErrorState.Success;

        } catch (Exception ex) {
            Logger.e("发送消息: ", ex);
        }

        return TcpErrorState.Error;
    }

    public void disconnect() {
        NettyManager.this
                .mChannelFuture.channel().close();
    }


    /**
     * TCP状态
     */
    @Getter
    @AllArgsConstructor
    public enum TcpErrorState {

        UnInitialized(-1, "未初始化"),
        Success(0, "通信成功"),
        Initialized(1, "初始化"),
        Connect(2, "正常连接完成"),
        Diconnect(3, "断开连接"),
        Error(-1, "发生异常");


        /**
         * 状态值
         */
        private final int state;

        /**
         * 状态值描述
         */
        private final String title;
    }
}
